package com.hgl.bi.web.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hgl.bi.common.annotation.RequirePmt;
import com.hgl.bi.common.constant.ErrorCode;
import com.hgl.bi.common.manager.RedisManager;
import com.hgl.bi.common.model.vo.R;
import com.hgl.bi.common.utils.AssertUtil;
import com.hgl.bi.web.entity.MetadataEntity;
import com.hgl.bi.web.entity.SetEntity;
import com.hgl.bi.web.mapper.MetadataMapper;
import com.hgl.bi.web.model.dto.*;
import com.hgl.bi.web.model.vo.SignatureVo;
import com.hgl.bi.web.service.MetadataService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List;
import java.util.Map;

/**
 * @program: BI
 * @description: 文件管理控制层
 * @author: hgl
 * @create: 2025-02-14 15:50
 */
@Tag(name = "文件管理模块")
@RestController
public class MetadataController {

    @Autowired
    private MetadataService metadataService;

    @Autowired
    private MetadataMapper metadataMapper;

    @Autowired
    private RedisManager redisManager;

    /**
     * 获取我的关联文件
     * @param id 数据集ID
     * @return 文件列表
     * @author hgl
     */
    @Operation(summary = "查询我的关联文件", tags = "文件管理模块")
    @GetMapping("/file/my/associate/{id}")
    public R<List<Long>> getMyAssociateFiles(@RequestHeader("satoken") String satoken,
                                             @PathVariable Long id) {
        UserInfoDto userInfo = (UserInfoDto) redisManager
                .get("satoken:" + satoken, UserInfoDto.class);
        long userId = userInfo.getId();

        List<Long> list = metadataService.getMyAssociateFiles(userId, id);
        return R.success(list);
    }

    /**
     * 获取我的文件
     * @return 文件列表
     * @author hgl
     */
    @Operation(summary = "查询我的文件", tags = "文件管理模块")
    @GetMapping("/file/my")
    public R<List<MetadataEntity>> getMyFiles(@RequestHeader("satoken") String satoken) {
        UserInfoDto userInfo = (UserInfoDto) redisManager
                .get("satoken:" + satoken, UserInfoDto.class);
        long userId = userInfo.getId();
        QueryWrapper<MetadataEntity> wrapper = new QueryWrapper<MetadataEntity>()
                .eq("user_id", userId)
                .eq("is_cleaned", 1);
        List<MetadataEntity> list = metadataService.list(wrapper);
        return R.success(list);
    }

    @Operation(summary = "统计数据清洗总数", tags = "文件管理模块")
    @GetMapping("/file/clean/count")
    public R<Long> countClean(@RequestHeader("satoken") String satoken) {
        UserInfoDto userInfo = (UserInfoDto) redisManager
                .get("satoken:" + satoken, UserInfoDto.class);
        long userId = userInfo.getId();
        Long count = metadataMapper.sumCleanCount(userId);
        return R.success(count);
    }

    /**
     * 统计总收入
     * @return 总收入
     */
    @Operation(summary = "统计总收入", tags = "文件管理模块")
    @GetMapping("/file/income")
    public R<Double> countIncome() {
        QueryWrapper<MetadataEntity> wrapper = new QueryWrapper<MetadataEntity>()
                .select("sum(income)");
        List<Object> objects = metadataMapper.selectObjs(wrapper);
        BigDecimal income = new BigDecimal(objects.get(0).toString());
        return R.success(income.doubleValue());
    }

    /**
     * 获取所有文件
     * @return 文件列表
     * @author hgl
     */
    @Operation(summary = "查询所有文件", tags = "文件管理模块")
    @GetMapping("/file/list/all")
    public R<List<MetadataEntity>> getFileNames(@RequestHeader("satoken") String satoken) {
        UserInfoDto userInfo = (UserInfoDto) redisManager
                .get("satoken:" + satoken, UserInfoDto.class);
        long userId = userInfo.getId();
        List<MetadataEntity> list;
        if (!userInfo.getRole().equals("admin")) {
            QueryWrapper<MetadataEntity> wrapper = new QueryWrapper<MetadataEntity>()
                    .eq("user_id", userId);
            list = metadataService.list(wrapper);
        } else {
            list = metadataService.list();
        }

        return R.success(list);
    }

    /**
     * 统计文件数量
     *
     * @return 文件数量
     */
    @Operation(summary = "统计文件数量", tags = "文件管理模块")
    @GetMapping("/file/sum")
    public R<Long> countSumFiles(@RequestHeader("satoken") String satoken) {
        UserInfoDto userInfo = (UserInfoDto) redisManager
                .get("satoken:" + satoken, UserInfoDto.class);
        long userId = userInfo.getId();
        long count;
        if (!userInfo.getRole().equals("admin")) {
            QueryWrapper<MetadataEntity> wrapper = new QueryWrapper<MetadataEntity>()
                    .eq("user_id", userId);
            count = metadataService.count(wrapper);
        } else {
            count = metadataService.count();
        }
        return R.success(count);
    }

    /**
     * 统计本月上传文件
     * @return 本月上传文件
     * @author hgl
     */
    @Operation(summary = "统计本月上传文件", tags = "文件管理模块")
    @GetMapping("/file/new")
    public R<Long> countNewFiles(@RequestHeader("satoken") String satoken) {
        // 获取当前日期
        LocalDate now = LocalDate.now();
        // 当前月份的第一天
        LocalDate startOfMonth = now.withDayOfMonth(1);
        // 当前月份的最后一天
        LocalDate endOfMonth = startOfMonth.plusMonths(1).minusDays(1);
        // 转换为 LocalDateTime
        LocalDateTime start = startOfMonth.atStartOfDay(); // 当月第一天 00:00:00
        LocalDateTime end = endOfMonth.atTime(LocalTime.MAX); // 当月最后一天 23:59:59
        QueryWrapper<MetadataEntity> wrapper = new QueryWrapper<MetadataEntity>()
                .ge("upload_time", start)
                .le("upload_time", end);
        UserInfoDto userInfo = (UserInfoDto) redisManager
                .get("satoken:" + satoken, UserInfoDto.class);
        long userId = userInfo.getId();
        long count;
        if (!userInfo.getRole().equals("admin")) {
            wrapper.eq("user_id", userId);
        }
        count = metadataService.count(wrapper);
        return R.success(count);
    }

    /**
     * 统计文件大小
     * @return 文件大小
     * @author hgl
     */
    @Operation(summary = "统计文件大小", tags = "文件管理模块")
    @GetMapping("/file/size")
    public R<Long> countFileSize(@RequestHeader("satoken") String satoken) {
        UserInfoDto userInfo = (UserInfoDto) redisManager
                .get("satoken:" + satoken, UserInfoDto.class);
        long userId = userInfo.getId();
        Long size = metadataMapper.sumFileSize(userId);
        return R.success(size);
    }

    /**
     * 关联文件
     * @param fileDto 数据集文件信息
     * @return R<String>
     * @author hgl
     */
    @Operation(summary = "关联文件", tags = "文件管理模块")
    @PutMapping("/file/associate")
    public R<String> associateFile(@RequestBody FileDto fileDto) {
        // 非空校验
        AssertUtil.notNull(fileDto, ErrorCode.REQUEST_PARAM_ERROR);
        // 分配权限
        metadataService.associateFile(fileDto);
        return R.ok("关联成功");
    }

    /**
     * 关联数据集权限
     * @param fileSetDto 数据集文件信息
     * @return R<String>
     * @author hgl
     */
    @Operation(summary = "关联数据集", tags = "文件管理模块")
    @PutMapping("/file/set")
    public R<String> associateSet(@RequestBody FileSetDto fileSetDto) {
        // 非空校验
        AssertUtil.notNull(fileSetDto, ErrorCode.REQUEST_PARAM_ERROR);
        // 分配权限
        metadataService.associateSet(fileSetDto);
        return R.ok("关联成功");
    }

    /**
     * 删除关联文件
     * @param fileDto 数据集文件信息
     * @return 提示信息
     */
    @Operation(summary = "删除关联文件", tags = "文件管理模块")
    @DeleteMapping("/file/associate/remove")
    public R<String> removeFiles(@RequestBody FileDto fileDto) {
        // 非空校验
        AssertUtil.notNull(fileDto, ErrorCode.REQUEST_PARAM_ERROR);
        // 删除关联文件
        metadataService.removeFiles(fileDto);
        return R.ok("删除成功");
    }

    /**
     * 删除关联数据集
     * @param fileSetDto 数据集文件信息
     * @return 提示信息
     */
    @Operation(summary = "删除关联数据集", tags = "文件管理模块")
    @DeleteMapping("/file/remove/set")
    public R<String> removeSets(@RequestBody FileSetDto fileSetDto) {
        // 非空校验
        AssertUtil.notNull(fileSetDto, ErrorCode.REQUEST_PARAM_ERROR);
        // 删除关联数据集
        metadataService.removeSets(fileSetDto);
        return R.ok("删除成功");
    }

    /**
     * 获取文件数据集
     * @param id 文件ID
     * @return 文件数据集
     */
    @Operation(summary = "查询文件数据集", tags = "文件管理模块")
    @GetMapping("/file/set/{id}")
    public R<List<Long>> getFileSets(@PathVariable Long id) {
        List<Long> sets = metadataMapper.selectFileSets(id);
        return R.success(sets);
    }

    /**
     * 获取COS上传签名
     *
     * @param signatureDto 文件信息
     * @return R<SignatureVo>
     * @author hgl
     */

    @Operation(summary = "获取COS上传签名", tags = "文件管理模块")
    @GetMapping("/file/cos/upload")
    @RequirePmt(code = "file:upload")
    public R<SignatureVo> getCosUploadSignature(@RequestHeader("satoken") String satoken,
                                                @ParameterObject SignatureDto signatureDto) {
        // 非空校验
        AssertUtil.notNull(signatureDto, ErrorCode.REQUEST_PARAM_ERROR);
        // 获取用户信息
        UserInfoDto userInfo = (UserInfoDto) redisManager
                .get("satoken:" + satoken, UserInfoDto.class);
        long userId = userInfo.getId();
        // 获取签名
        SignatureVo signatureVo = metadataService.getCosUploadSignature(signatureDto, userId);
        return R.success(signatureVo);
    }

    /**
     * 获取COS签名
     *
     * @param cosPath cos存储路径
     * @return R<String>
     * @author hgl
     */
    @Operation(summary = "获取COS下载签名", tags = "文件管理模块")
    @GetMapping("/file/cos/download")
    public R<String> getCosDownloadSignature(@RequestParam String cosPath) {
        // 非空校验
        AssertUtil.notNull(cosPath, ErrorCode.REQUEST_PARAM_ERROR);
        // 获取签名
        String signature = metadataService.getCosDownloadSignature(cosPath);
        return R.success(signature);
    }

    /**
     * 保存文件路径
     *
     * @param pathDto 文件路径信息
     * @return R<String>
     * @author hgl
     */
    @Operation(summary = "保存文件路径", tags = "文件管理模块")
    @PostMapping("/file/path/save")
    public R<String> saveFilePath(@RequestHeader("satoken") String satoken,
                                  @RequestBody PathDto pathDto) {
        // 非空校验
        AssertUtil.notNull(pathDto, ErrorCode.REQUEST_PARAM_ERROR);
        UserInfoDto userInfo = (UserInfoDto) redisManager
                .get("satoken:" + satoken, UserInfoDto.class);
        // 获取用户信息
        long userId = userInfo.getId();
        // 保存文件路径
        metadataService.saveFilePath(pathDto, userId);
        return R.ok("保存成功");
    }

    /**
     * 分页查询文件元数据列表
     *
     * @param pageDto 分页信息
     * @return 文件元数据分页信息
     * @author hgl
     */
    @Operation(summary = "查询元数据列表", tags = "文件管理模块")
    @GetMapping("/file/list")
    public R<Page<MetadataEntity>> listFiles(@RequestHeader("satoken") String satoken,
                                             @ParameterObject FilePageDTO pageDto) {
        // 非空校验
        AssertUtil.notNull(pageDto, ErrorCode.REQUEST_PARAM_ERROR);
        // 分页查询
        Page<MetadataEntity> page = new Page<>(pageDto.getPage(), pageDto.getSize());
        UserInfoDto userInfo = (UserInfoDto) redisManager
                .get("satoken:" + satoken, UserInfoDto.class);
        long userId = userInfo.getId();
        QueryWrapper<MetadataEntity> wrapper = new QueryWrapper<MetadataEntity>()
                .eq("user_id", userId);
        if (pageDto.getKeyword() != null && !pageDto.getKeyword().isEmpty()) wrapper
                .like("file_name", pageDto.getKeyword())
                .or()
                .like("file_type", pageDto.getKeyword());
        Page<MetadataEntity> filePage = metadataService.page(page, wrapper);
        return R.success(filePage);
    }

    /**
     * 获取文件内容
     *
     * @param id 文件ID
     * @return R<List<Map<Integer, String>>>
     * @author hgl
     */
    @Operation(summary = "查询文件内容", tags = "文件管理模块")
    @GetMapping("/file/content/{id}")
    public R<List<Map<Integer, String>>> getFileContent(@PathVariable Long id) {
        // 非空校验
        AssertUtil.notNull(id, ErrorCode.REQUEST_PARAM_ERROR);
        // 查询文件内容
        List<Map<Integer, String>> content = metadataService.getFileContent(id);
        return R.success(content);
    }

    /**
     * 获取清洗后文件内容
     *
     * @param id 文件ID
     * @return R<List<Map<Integer, String>>>
     * @author hgl
     */
    @Operation(summary = "查询清洗后文件内容", tags = "文件管理模块")
    @GetMapping("/file/clean/content/{id}")
    public R<List<Map<Integer, String>>> getCleanFileContent(@PathVariable Long id) {
        // 非空校验
        AssertUtil.notNull(id, ErrorCode.REQUEST_PARAM_ERROR);
        // 查询文件内容
        List<Map<Integer, String>> content = metadataService.getCleanFileContent(id);
        return R.success(content);
    }

    /**
     * 更新文件数据信息
     *
     * @param dto 文件元数据
     * @return R<String>
     * @author hgl
     */
    @Operation(summary = "更新文件元数据", tags = "文件管理模块")
    @PostMapping("/file/update")
    public R<String> updateMetadata(@RequestBody MetadataDto dto) {
        // 非空校验
        AssertUtil.notNull(dto, ErrorCode.REQUEST_PARAM_ERROR);
        // 更新文件
        String fileName = dto.getFileName();
        String desc = dto.getFileDesc();
        UpdateWrapper<MetadataEntity> wrapper = new UpdateWrapper<MetadataEntity>()
                .eq("id", dto.getId());
        if (fileName != null && !fileName.isEmpty()) wrapper.set("file_name", fileName);
        if (desc != null && !desc.isEmpty()) wrapper.set("file_desc", desc);
        boolean updated = metadataService.update(wrapper);
        AssertUtil.isTrue(updated, ErrorCode.UPDATE_FALSE);
        return R.ok("更新成功");
    }

    /**
     * 删除文件数据信息
     *
     * @param id 文件ID
     * @return R<String>
     * @author hgl
     */
    @Operation(summary = "删除文件元数据", tags = "文件管理模块")
    @DeleteMapping("/file/remove/{id}")
    public R<String> removeFile(@PathVariable String id) {
        // 非空校验
        AssertUtil.notNull(id, ErrorCode.REQUEST_PARAM_ERROR);
        // 删除文件
        metadataService.removeById(id);
        return R.ok("删除成功");
    }
}
